package com.qingzhuge.netty.client;

import com.qingzhuge.netty.common.autoconfigure.NettyServerProperties;
import io.netty.bootstrap.Bootstrap;
import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelInitializer;
import io.netty.channel.ChannelOption;
import io.netty.channel.EventLoopGroup;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.nio.NioSocketChannel;
import io.netty.util.HashedWheelTimer;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;

import java.net.InetSocketAddress;
import java.util.concurrent.TimeUnit;

/**
 * @author : zero.xiao
 * @description :
 * @date :2018/9/28 0028 下午 15:20
 * @modified :
 * @since : 1.0.0
 */
public class NettyClient {

    private final static Logger log = LoggerFactory.getLogger(NettyClient.class);

    @Autowired
    private NettyServerProperties properties;

    /**
     * EventLoopGroup可以理解为是一个线程池，这个线程池用来处理连接、接受数据、发送数据
     * 客户端引导类
     */
    private EventLoopGroup workGroup = new NioEventLoopGroup();

    public void start() {
        Bootstrap bootstrap = getBootstrap();
        String host = properties.getHost();
        int port = properties.getPort();
        InetSocketAddress address;
        if (StringUtils.isEmpty(host)) {
            address = new InetSocketAddress(port);
            bootstrap.remoteAddress(address);
            log.debug("Netty server start >>> 0.0.0.0:{}", port);
        } else {
            // 服务器绑定IP/端口监听
            address = new InetSocketAddress(host, port);
            bootstrap.remoteAddress(address);
            log.debug("Netty server start >>> {}:{}", host, port);
        }
        NettyServerHandler handler = new NettyServerHandler(bootstrap, properties, new HashedWheelTimer(), address);
        ChannelFuture future;
        try {
            synchronized (this) {
                bootstrap.handler(new ChannelInitializer<NioSocketChannel>() {

                    @Override
                    protected void initChannel(NioSocketChannel ch) {
                        ch.pipeline().addLast(handler.handlers());
                    }
                });
                // 链接服务器.调用sync()方法会同步阻塞
                future = bootstrap.connect().sync();
            }

            if (!future.isSuccess()) {
                log.info("---- 连接服务器失败,2秒后重试 ---------port=" + port);
                future.channel().eventLoop().schedule(this::start, 2L, TimeUnit.SECONDS);
            }

        } catch (Exception e) {
            log.error("exception happends e {}", e.getMessage());
        }

    }


    private Bootstrap getBootstrap() {
        Bootstrap bootstrap = new Bootstrap();
        bootstrap.group(workGroup)
                .channel(NioSocketChannel.class)
                //针对主线程的配置 分配线程最大线程数
                .option(ChannelOption.SO_BACKLOG, 128);
        return bootstrap;
    }

}
